const express = require("express");
const fs = require("fs");
const { createServer } = require("vite");
const path = require("path");

const router = express.Router({ caseSensitive: true });

async function createViteServer() {
  // 以中间件模式创建 vite 服务器
  const vite = await createServer({
    server: {
      middlewareMode: "ssr",
    },
    appType: "custom",
  });

  // 将 vite 的 connect 实例作中间件使用
  router.use(vite.middlewares);

  router.get("*", async (req, res) => {
    const url = req.originalUrl;

    try {
      // 1. 读取 index.html
      let template = fs.readFileSync(
        path.join(__dirname, "../../index.html"),
        "utf-8"
      );

      // 2. 应用 vite HTML 转换。这将会注入 vite HMR 客户端，
      //    同时也会从 Vite 插件应用 HTML 转换。
      //    例如：@vitejs/plugin-react-refresh 中的 global preambles
      template = await vite.transformIndexHtml(url, template);

      // 3. 加载服务器入口。vite.ssrLoadModule 将自动转换
      //    你的 ESM 源码使之可以在 Node.js 中运行！无需打包
      //    并提供类似 HMR 的根据情况随时失效。
      const { render } = await vite.ssrLoadModule("/src/entry-server.js");

      // 4. 渲染应用的 HTML。这假设 entry-server.js 导出的 `render`
      //    函数调用了适当的 SSR 框架 API。
      //    例如 ReactDOMServer.renderToString()

      let ctx = {};
      const { appHtml } = await render(url, ctx, {});

      if (ctx.url) {
        res.redirect(301, ctx.url);
        res.end();
      } else {
        const { $meta, state } = ctx;
        // console.log('state 22222222>>>>', state);
        const metaInfo = $meta.get(url);
        const html = template
          .replace(`<!--title-outlet-->`, metaInfo.title)
          .replace(`<!--meta-outlet-->`, genMetaTagsStr(metaInfo.meta))
          .replace(
            `<!--init-state-->`,
            `<script>var __INITIAL_STATE__ = ${JSON.stringify(state)}</script>`
          )
          .replace('<div id="app">', `<div id="app">${appHtml}`); // 用注释替换，spa模式下会有Hydration 警告
        // console.log('html>>>', html);

        res.status(200).set({ "Content-Type": "text/html" }).end(html);
      }
    } catch (e) {
      // 如果捕获到了一个错误，让 vite 来修复该堆栈，这样它就可以映射回
      // 你的实际源码中。
      vite.ssrFixStacktrace(e);
      console.error(e);
      res.status(500).end(e.message);
    }
  });
}
createViteServer();

function genMetaTagsStr(metas = []) {
  if (metas.length) {
    return metas
      .map((item) => `<meta name='${item.name}' content='${item.content}'>`)
      .join("\n");
  }
  return "";
}

module.exports = router;
